part of 'page.dart';

class _SingleWordBasePageWloc extends StatefulWloc<_SingleWordBasePageWlocState, SingleWordBasePage>
    with TickerProviderStateMixin {
  late final bloc.SingleWordBasePageBloc _bloc;
  late final FocusNode _keyboardListenerFocusNode;

  late _WordBaseInputPresentationModel wordBaseInputPresentationModel;

  @override
  _SingleWordBasePageWlocState get initialState {
    return _SingleWordBasePageWlocStateFactory().create(
      blocState: _bloc.state,
    );
  }

  void onBackButtonPressed() {
    _bloc.requestPageClosing();
  }

  void onWordImageChangeButtonPressed({
    required String imagePath,
  }) {
    _bloc.requestWordImageChange(
      imagePath: imagePath,
    );
  }

  void onWordImageDeletionButtonPressed() {
    _bloc.requestWordImageDeletion();
  }

  void onPartOfSpeechChanged({
    required PartOfSpeech partOfSpeech,
  }) {
    _bloc.requestWordBaseInputPartOfSpeechUpdate(
      partOfSpeech: partOfSpeech,
    );
  }

  void onCefrLevelChanged({
    required CefrLevel cefrLevel,
  }) {
    _bloc.requestWordBaseInputCefrLevelUpdate(
      cefrLevel: cefrLevel,
    );
  }

  void onUseCaseDeletionButtonPressed({
    required int index,
  }) {
    final useCaseInputId = wordBaseInputPresentationModel.useCaseInputPresentationModels[index].id;

    _bloc.requestUseCaseInputDeletion(
      useCaseInputId: useCaseInputId,
    );
  }

  void onUseCasePromotionButtonPressed({
    required int index,
  }) {
    final useCaseInputId = wordBaseInputPresentationModel.useCaseInputPresentationModels[index].id;

    _bloc.requestUseCaseInputPromotion(
      useCaseInputId: useCaseInputId,
    );
  }

  void onUseCaseAdditionButtonPressed() {
    _bloc.requestUseCaseInputAddition();
  }

  Key getUseCaseInputKey(String id) {
    return ValueKey(id);
  }

  bool onReorderUseCaseInputs(Key draggedItemKey, Key newPositionKey) {
    final firstUseCaseInputId = (draggedItemKey as ValueKey<String>).value;
    final secondUseCaseInputId = (newPositionKey as ValueKey<String>).value;

    _bloc.requestUseCaseInputSwap(
      firstUseCaseInputId: firstUseCaseInputId,
      secondUseCaseInputId: secondUseCaseInputId,
    );

    return true;
  }

  KeyEventResult _handleKeyEvent(KeyEvent keyEvent) {
    if (keyEvent.physicalKey == PhysicalKeyboardKey.escape) {
      if (keyEvent is KeyUpEvent) {
        FocusScope.of(context).unfocus();
        _bloc.requestPageClosing();
      }

      return KeyEventResult.handled;
    }

    if (keyEvent.physicalKey == PhysicalKeyboardKey.arrowLeft) {
      if (keyEvent is KeyUpEvent) {
        FocusScope.of(context).unfocus();
        _bloc.requestPreviousWordBasePageOpening();
      }

      return KeyEventResult.handled;
    }

    if (keyEvent.physicalKey == PhysicalKeyboardKey.arrowRight) {
      if (keyEvent is KeyUpEvent) {
        FocusScope.of(context).unfocus();
        _bloc.requestNextWordBasePageOpening();
      }

      return KeyEventResult.handled;
    }

    return KeyEventResult.ignored;
  }

  void _onWordTitleChanged() {
    _bloc.requestWordBaseInputTitleUpdate(
      titleInputText: wordBaseInputPresentationModel.titleTextEditingController.text,
    );
  }

  void _onWordAmTranscriptionChanged() {
    _bloc.requestWordBaseInputAmTranscriptionUpdate(
      amTranscriptionInputText:
          wordBaseInputPresentationModel.amTranscriptionTextEditingController.text,
    );
  }

  void _onWordBrTranscriptionChanged() {
    _bloc.requestWordBaseInputBrTranscriptionUpdate(
      brTranscriptionInputText:
          wordBaseInputPresentationModel.brTranscriptionTextEditingController.text,
    );
  }

  void _onWordRankChanged() {
    _bloc.requestWordBaseInputRankUpdate(
      rankInputText: wordBaseInputPresentationModel.rankTextEditingController.text,
    );
  }

  void _onWordDefinitionChanged() {
    _bloc.requestWordBaseInputDefinitionUpdate(
      definitionInputText: wordBaseInputPresentationModel.definitionTextEditingController.text,
    );
  }

  void _onUseCaseExampleMarkdownChanged({
    required String id,
    required TextEditingController exampleMarkdownTextEditingController,
  }) {
    _bloc.requestUseCaseInputExampleMarkdownUpdate(
      useCaseExampleMarkdownInputText: exampleMarkdownTextEditingController.text,
      useCaseInputId: id,
    );
  }

  void _disposeUseCasePresentationModel({
    required _UseCaseInputPresentationModel useCaseInputPresentationModel,
  }) {
    useCaseInputPresentationModel.appearanceAnimationController.dispose();
    useCaseInputPresentationModel.exampleMarkdownTextEditingController.dispose();
  }

  void _removeUseCasePresentationModel({
    required String id,
  }) {
    final useCaseInputPresentationModels =
        wordBaseInputPresentationModel.useCaseInputPresentationModels;

    final updatedUseCaseInputPresentationModels = <_UseCaseInputPresentationModel>[];
    late final _UseCaseInputPresentationModel toBeDeletedUseCaseInputPresentationModel;

    for (final useCaseInputPresentationModel in useCaseInputPresentationModels) {
      if (useCaseInputPresentationModel.id == id) {
        toBeDeletedUseCaseInputPresentationModel = useCaseInputPresentationModel;
      } else {
        updatedUseCaseInputPresentationModels.add(useCaseInputPresentationModel);
      }
    }

    setState(() {
      wordBaseInputPresentationModel = wordBaseInputPresentationModel.copyWith(
        useCaseInputPresentationModels: () => updatedUseCaseInputPresentationModels.build(),
      );
    });

    WidgetsBinding.instance.addPostFrameCallback((_) {
      _disposeUseCasePresentationModel(
        useCaseInputPresentationModel: toBeDeletedUseCaseInputPresentationModel,
      );
    });
  }

  _UseCaseInputPresentationModel _createUseCaseInputPresentationModel({
    required WordBaseUseCaseInput useCaseInput,
  }) {
    final appearanceAnimationController = AnimationController(
      // duration: const Duration(milliseconds: 200),
      duration: Duration.zero,
      vsync: this,
    );

    final appearanceAnimation = CurvedAnimation(
      parent: appearanceAnimationController,
      curve: Curves.easeOut,
      reverseCurve: Curves.easeOut.flipped,
    );

    final exampleMarkdownTextEditingController = TextEditingController(
      text: useCaseInput.exampleMarkdown,
    );

    exampleMarkdownTextEditingController.addListener(() {
      _onUseCaseExampleMarkdownChanged(
        id: useCaseInput.id,
        exampleMarkdownTextEditingController: exampleMarkdownTextEditingController,
      );
    });

    return _UseCaseInputPresentationModel(
      id: useCaseInput.id,
      exampleMarkdownTextEditingController: exampleMarkdownTextEditingController,
      exampleMarkdownTextFieldFocusNode: FocusNode(),
      appearanceAnimationController: appearanceAnimationController,
      appearanceAnimation: appearanceAnimation,
      markedToDelete: false,
    );
  }

  _WordBaseInputPresentationModel _createWordBaseInputPresentationModel({
    required WordBaseInput wordBaseInput,
  }) {
    final titleTextEditingController = TextEditingController(
      text: wordBaseInput.title,
    );

    final amTranscriptionTextEditingController = TextEditingController(
      text: wordBaseInput.amTranscription,
    );

    final brTranscriptionTextEditingController = TextEditingController(
      text: wordBaseInput.brTranscription,
    );

    final rankTextEditingController = TextEditingController(
      text: wordBaseInput.rank == null ? '' : wordBaseInput.rank.toString(),
    );

    final definitionTextEditingController = TextEditingController(
      text: wordBaseInput.definition,
    );

    titleTextEditingController.addListener(_onWordTitleChanged);
    amTranscriptionTextEditingController.addListener(_onWordAmTranscriptionChanged);
    brTranscriptionTextEditingController.addListener(_onWordBrTranscriptionChanged);
    rankTextEditingController.addListener(_onWordRankChanged);
    definitionTextEditingController.addListener(_onWordDefinitionChanged);

    final useCaseInputPresentationModels = wordBaseInput.useCaseInputs.map((useCaseInput) {
      final useCaseInputPresentationModel = _createUseCaseInputPresentationModel(
        useCaseInput: useCaseInput,
      );

      useCaseInputPresentationModel.appearanceAnimationController.value = 1.0;

      return useCaseInputPresentationModel;
    }).toBuiltList();

    return _WordBaseInputPresentationModel(
      titleTextEditingController: titleTextEditingController,
      titleTextFieldFocusNode: FocusNode(),
      amTranscriptionTextEditingController: amTranscriptionTextEditingController,
      amTranscriptionTextFieldFocusNode: FocusNode(),
      brTranscriptionTextEditingController: brTranscriptionTextEditingController,
      brTranscriptionTextFieldFocusNode: FocusNode(),
      rankTextEditingController: rankTextEditingController,
      rankTextFieldFocusNode: FocusNode(),
      definitionTextEditingController: definitionTextEditingController,
      definitionTextFieldFocusNode: FocusNode(),
      useCaseInputPresentationModels: useCaseInputPresentationModels,
    );
  }

  void _handleWordBaseInputUpdate({
    required WordBaseInput updatedWordBaseInput,
  }) {
    if (wordBaseInputPresentationModel.titleTextEditingController.text !=
        updatedWordBaseInput.title) {
      wordBaseInputPresentationModel.titleTextEditingController.value = TextEditingValue(
        text: updatedWordBaseInput.title,
        selection: TextSelection.collapsed(
          offset: updatedWordBaseInput.title.length,
        ),
      );
    }

    if (wordBaseInputPresentationModel.amTranscriptionTextEditingController.text !=
        updatedWordBaseInput.amTranscription) {
      wordBaseInputPresentationModel.amTranscriptionTextEditingController.value = TextEditingValue(
        text: updatedWordBaseInput.amTranscription,
        selection: TextSelection.collapsed(
          offset: updatedWordBaseInput.amTranscription.length,
        ),
      );
    }

    if (wordBaseInputPresentationModel.brTranscriptionTextEditingController.text !=
        updatedWordBaseInput.brTranscription) {
      wordBaseInputPresentationModel.brTranscriptionTextEditingController.value = TextEditingValue(
        text: updatedWordBaseInput.brTranscription,
        selection: TextSelection.collapsed(
          offset: updatedWordBaseInput.brTranscription.length,
        ),
      );
    }

    final updatedWordBaseInputRankText =
        updatedWordBaseInput.rank == null ? '' : updatedWordBaseInput.rank.toString();

    if (wordBaseInputPresentationModel.rankTextEditingController.text !=
        updatedWordBaseInputRankText) {
      wordBaseInputPresentationModel.rankTextEditingController.value = TextEditingValue(
        text: updatedWordBaseInputRankText,
        selection: TextSelection.collapsed(
          offset: updatedWordBaseInputRankText.length,
        ),
      );
    }

    final useCaseInputPresentationModels =
        wordBaseInputPresentationModel.useCaseInputPresentationModels;

    final updatedUseCasePresentationModels = <_UseCaseInputPresentationModel>[];

    final updatedUseCaseInputs = updatedWordBaseInput.useCaseInputs;

    for (final updatedUseCaseInput in updatedUseCaseInputs) {
      _UseCaseInputPresentationModel? correspondingUseCaseInputPresentationModel;

      for (final useCaseInputPresentationModel in useCaseInputPresentationModels) {
        if (useCaseInputPresentationModel.id == updatedUseCaseInput.id) {
          correspondingUseCaseInputPresentationModel = useCaseInputPresentationModel;
          break;
        }
      }

      if (correspondingUseCaseInputPresentationModel == null) {
        correspondingUseCaseInputPresentationModel = _createUseCaseInputPresentationModel(
          useCaseInput: updatedUseCaseInput,
        );

        correspondingUseCaseInputPresentationModel.appearanceAnimationController.forward(from: 0.0);
      } else if (correspondingUseCaseInputPresentationModel
              .exampleMarkdownTextEditingController.text !=
          updatedUseCaseInput.exampleMarkdown) {
        correspondingUseCaseInputPresentationModel.exampleMarkdownTextEditingController.value =
            TextEditingValue(
          text: updatedUseCaseInput.exampleMarkdown,
          selection: TextSelection.collapsed(
            offset: updatedUseCaseInput.exampleMarkdown.length,
          ),
        );
      }

      updatedUseCasePresentationModels.add(correspondingUseCaseInputPresentationModel);
    }

    for (var i = 0; i < useCaseInputPresentationModels.length; i++) {
      final useCaseInputPresentationModel = useCaseInputPresentationModels[i];

      final bool useCaseInputPresentationModelExists;

      if (useCaseInputPresentationModel.markedToDelete) {
        useCaseInputPresentationModelExists = false;
      } else {
        useCaseInputPresentationModelExists = updatedUseCaseInputs.any((updatedUseCaseInput) {
          return updatedUseCaseInput.id == useCaseInputPresentationModel.id;
        });
      }

      if (!useCaseInputPresentationModelExists) {
        final int updatedUseCasePresentationModelIndex;

        String? previousUseCaseInputPresentationModelId;

        if (i > 0) {
          previousUseCaseInputPresentationModelId = useCaseInputPresentationModels[i - 1].id;
        }

        if (previousUseCaseInputPresentationModelId == null) {
          updatedUseCasePresentationModelIndex = 0;
        } else {
          final index =
              updatedUseCasePresentationModels.indexWhere((updatedUseCasePresentationModel) {
            return updatedUseCasePresentationModel.id == previousUseCaseInputPresentationModelId;
          });

          updatedUseCasePresentationModelIndex = index + 1;
        }

        final _UseCaseInputPresentationModel updatedUseCaseInputPresentationModel;

        if (useCaseInputPresentationModel.markedToDelete) {
          updatedUseCaseInputPresentationModel = useCaseInputPresentationModel;
        } else {
          updatedUseCaseInputPresentationModel = useCaseInputPresentationModel.copyWith(
            markedToDelete: () => true,
          );

          updatedUseCaseInputPresentationModel.appearanceAnimationController
              .reverse()
              .whenComplete(() {
            _removeUseCasePresentationModel(
              id: updatedUseCaseInputPresentationModel.id,
            );
          });
        }

        updatedUseCasePresentationModels.insert(
            updatedUseCasePresentationModelIndex, updatedUseCaseInputPresentationModel);
      }
    }

    setState(() {
      wordBaseInputPresentationModel = wordBaseInputPresentationModel.copyWith(
        useCaseInputPresentationModels: () => updatedUseCasePresentationModels.build(),
      );
    });
  }

  void _onBlocStateChanged(
      (bloc.SingleWordBasePageBlocState, bloc.SingleWordBasePageBlocState) valueWithPrevious) {
    final (blocState, blocPreviousState) = valueWithPrevious;

    if (blocPreviousState.wordBaseInput != blocState.wordBaseInput) {
      _handleWordBaseInputUpdate(
        updatedWordBaseInput: blocState.wordBaseInput,
      );
    }

    final updatedState = _SingleWordBasePageWlocStateFactory().create(
      blocState: blocState,
    );

    emit(updatedState);
  }

  @override
  void initState() {
    super.initState();

    _bloc = bloc.SingleWordBasePageBloc(
      pageModel: widget.pageModel,
      learningContentBloc: core_di.sl(),
      rootNavigatorBloc: core_di.sl(),
      getInitialData: single_word_base_page_di.sl(),
      initialize: single_word_base_page_di.sl(),
      addUseCaseInput: single_word_base_page_di.sl(),
      changeWordImage: single_word_base_page_di.sl(),
      deleteUseCaseInput: single_word_base_page_di.sl(),
      deleteWordImage: single_word_base_page_di.sl(),
      handleCachedLexicalItemImagePathMapOuterUpdate: single_word_base_page_di.sl(),
      handleLearningContentOuterUpdate: single_word_base_page_di.sl(),
      handleLexicalItemImageBankOuterUpdate: single_word_base_page_di.sl(),
      handleNextWordBasePageOpeningRequest: single_word_base_page_di.sl(),
      handlePageClosingRequest: single_word_base_page_di.sl(),
      handlePreviousWordBasePageOpeningRequest: single_word_base_page_di.sl(),
      promoteUseCaseInput: single_word_base_page_di.sl(),
      swapUseCaseInputs: single_word_base_page_di.sl(),
      updateUseCaseInputExampleMarkdown: single_word_base_page_di.sl(),
      updateWordBaseInputAmTranscription: single_word_base_page_di.sl(),
      updateWordBaseInputBrTranscription: single_word_base_page_di.sl(),
      updateWordBaseInputCefrLevel: single_word_base_page_di.sl(),
      updateWordBaseInputDefinition: single_word_base_page_di.sl(),
      updateWordBaseInputPartOfSpeech: single_word_base_page_di.sl(),
      updateWordBaseInputRank: single_word_base_page_di.sl(),
      updateWordBaseInputTitle: single_word_base_page_di.sl(),
    );

    _bloc.streamWithPrevious.listen(_onBlocStateChanged);

    wordBaseInputPresentationModel = _createWordBaseInputPresentationModel(
      wordBaseInput: _bloc.state.wordBaseInput,
    );

    _keyboardListenerFocusNode = FocusNode();
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _keyboardListenerFocusNode.requestFocus();
  }

  @override
  void dispose() {
    _bloc.close();
    _keyboardListenerFocusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Focus(
      focusNode: _keyboardListenerFocusNode,
      onKeyEvent: (FocusNode node, KeyEvent event) {
        return _handleKeyEvent(event);
      },
      child: Localizations.override(
        context: context,
        delegates: [
          _SingleWordBasePageTranslation.delegate,
        ],
        child: _SingleWordBasePageTheme(
          brightness: CoreTheme.of(context).brightness,
          child: _SingleWordBasePageView(
            wloc: this,
          ),
        ),
      ),
    );
  }
}
